﻿using System.Security.Cryptography;
using System.Text;

namespace Untils
{
    /// <summary>
    /// 加解密通用方法
    /// </summary>
    public class EncryptHelper
    {
        #region DES 加解密算法

        //默认密钥向量
        private static readonly byte[] Keys = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };

        /// <summary>
        /// DES加密字符串
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥,要求为16位</param>
        /// <returns>加密成功返回加密后的字符串，失败返回源串</returns>
        public static string DESEncrypt(string encryptString, string encryptKey = "XinHai#KeYue#Key")
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 16));
                byte[] rgbIV = Keys;
                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
                Aes DCSP = Aes.Create();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Convert.ToBase64String(mStream.ToArray());
            }
            catch (Exception ex)
            {
                return ex.Message + encryptString;
            }
        }

        /// <summary>
        /// DES解密字符串
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥,要求为16位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串，失败返源串</returns>
        public static string DESDecrypt(string decryptString, string decryptKey = "XinHai#KeYue#Key")
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 16));
                byte[] rgbIV = Keys;
                byte[] inputByteArray = Convert.FromBase64String(decryptString);
                Aes DCSP = Aes.Create();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                byte[] inputByteArrays = new byte[inputByteArray.Length];
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Encoding.UTF8.GetString(mStream.ToArray());
            }
            catch (Exception ex)
            {
                return ex.Message + decryptString;
            }
        }

        #endregion DES 加解密算法

        private static string Md5Key(string key)
        {
            byte[] b = Encoding.Default.GetBytes(key);
            b = new MD5CryptoServiceProvider().ComputeHash(b);
            string ret = "";
            for (int i = 0; i < b.Length; i++)
            {
                ret += b[i].ToString("x").PadLeft(2, '0');
            }
            return ret;
        }        

        #region Md5可逆加解密

        /// <summary>
        /// Md5加密
        /// </summary>
        /// <param name="strInput">要加密的文本</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string Md5Encrypt(string strInput, string key)
        {
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            byte[] inputByteArray = Encoding.Default.GetBytes(strInput);
            des.Key = ASCIIEncoding.ASCII.GetBytes(Md5Key(key).Substring(0, 8));
            des.IV = ASCIIEncoding.ASCII.GetBytes(Md5Key(key).Substring(0, 8));
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            StringBuilder ret = new StringBuilder();
            foreach (byte b in ms.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }
            return ret.ToString();
        }

        /// <summary>
        /// md5加密
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static string Md5Encrypt(byte[] content)
        {
            var md5Hasher = MD5.Create();
            byte[] data = md5Hasher.ComputeHash(content);
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString().Replace("-", "");
        }

        /// <summary>
        /// Md5解密
        /// </summary>
        /// <param name="strInput">要加密的文本</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static string Md5Decrypt(string strInput, string key)
        {
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            byte[] inputByteArray = new byte[strInput.Length / 2];
            for (int x = 0; x < strInput.Length / 2; x++)
            {
                int i = (Convert.ToInt32(strInput.Substring(x * 2, 2), 16));
                inputByteArray[x] = (byte)i;
            }

            des.Key = ASCIIEncoding.ASCII.GetBytes(Md5Key(key).Substring(0, 8));
            des.IV = ASCIIEncoding.ASCII.GetBytes(Md5Key(key).Substring(0, 8));
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            return Encoding.Default.GetString(ms.ToArray());
        }
        /// <summary>
        /// Md5解密
        /// </summary>
        /// <param name="strInput">要加密的文本</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        public static Tuple<bool, string> Md5DecryptHeavy(string strInput, string key)
        {
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            try
            {
                byte[] inputByteArray = new byte[strInput.Length / 2];
                for (int x = 0; x < strInput.Length / 2; x++)
                {
                    int i = (Convert.ToInt32(strInput.Substring(x * 2, 2), 16));
                    inputByteArray[x] = (byte)i;
                }

                des.Key = ASCIIEncoding.ASCII.GetBytes(Md5Key(key).Substring(0, 8));
                des.IV = ASCIIEncoding.ASCII.GetBytes(Md5Key(key).Substring(0, 8));
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                return new Tuple<bool, string>(true, Encoding.Default.GetString(ms.ToArray()));
            }
            catch (Exception)
            {
                return new Tuple<bool, string>(false, "");
            }
        }
        #endregion Md5可逆加解密

        #region MD5不可逆 用户密码加密比对

        /// <summary>
        /// MD5加密无碰撞,不可逆
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <returns>Md5加密后的字符串</returns>
        /// 无碰撞是指：7ac66c0f148de9519b8bd264312c4d64 这段密文 只能由 abcdefg 这段明文得到，除此之外其他的 明文加密后 其值 绝对不会等于7ac66c0f148de9519b8bd264312c4d64，也就是说 没有那两个明文 加密后 会得到相同的密文。
        /// 不可逆是指：明文通过加密后得到密文，而无法通过密文 求出明文。也就是说 当我们知道明文 adcdefg 可以通过加密得到 7ac66c0f148de9519b8bd264312c4d64，但是我们如果知道 某段文字 加密后 得到7ac66c0f148de9519b8bd264312c4d64，却无法算出 7ac66c0f148de9519b8bd264312c4d64这段文字是由谁加密而来的。
        public static string Md5HashEncrypt(string encryptString)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] result = md5.ComputeHash(Encoding.ASCII.GetBytes(encryptString));
                string strResult = BitConverter.ToString(result);
                return strResult.Replace("-", "");
            }
        }

        public static string Md5HashEncryptCN(string encryptString)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] result = md5.ComputeHash(Encoding.UTF8.GetBytes(encryptString));
                string strResult = BitConverter.ToString(result);
                return strResult.Replace("-", "");
            }
        }

        #endregion MD5不可逆 用户密码加密比对

        #region AES加解密算法

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="text">加密字符串</param>
        /// <param name="key">加密Key</param>
        /// <param name="iv">密钥</param>
        /// <returns></returns>
        public static string AESEncrypt(string text, string key, string iv)
        {
            byte[] sourceBytes = Encoding.UTF8.GetBytes(text);
            Aes aes = Aes.Create();
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = Encoding.UTF8.GetBytes(key);
            aes.IV = Encoding.UTF8.GetBytes(iv);
            ICryptoTransform transform = aes.CreateEncryptor();
            return System.Convert.ToBase64String(transform.TransformFinalBlock(sourceBytes, 0, sourceBytes.Length));
        }

        public static string AES256Encrypt(string text, string key, string iv)
        {
            byte[] sourceBytes = Encoding.UTF8.GetBytes(text);
            Aes aes = Aes.Create();
            aes.KeySize = 256; // 设置加密算法的密钥大小为256位
            aes.BlockSize = 128; // 设置加密算法的分组大小为128位
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = Convert.FromBase64String(key);
            aes.IV = Convert.FromBase64String(iv);
            ICryptoTransform transform = aes.CreateEncryptor();
            return System.Convert.ToBase64String(transform.TransformFinalBlock(sourceBytes, 0, sourceBytes.Length));
        }

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="text">解密字符串</param>
        /// <param name="key">解密Key</param>
        /// <param name="iv">密钥</param>
        /// <returns></returns>
        public static string AESDecrypt(string text, string key, string iv)
        {
            byte[] encryptBytes = Convert.FromBase64String(text);
            Aes aes = Aes.Create();
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = Encoding.UTF8.GetBytes(key);
            aes.IV = Encoding.UTF8.GetBytes(iv);
            ICryptoTransform transform = aes.CreateDecryptor();
            return Encoding.UTF8.GetString(transform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length));
        }

        public static string AES256Decrypt(string text, string key, string iv)
        {
            byte[] encryptBytes = Convert.FromBase64String(text);
            Aes aes = Aes.Create();
            aes.KeySize = 256; // 设置加密算法的密钥大小为256位
            aes.BlockSize = 128; // 设置加密算法的分组大小为128位
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = Convert.FromBase64String(key);
            aes.IV = Convert.FromBase64String(iv);
            ICryptoTransform transform = aes.CreateDecryptor();
            return Encoding.UTF8.GetString(transform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length));
        }

        #endregion AES加解密算法
    }
}
